home *** CD-ROM | disk | FTP | other *** search
- //--------------------------------------------------------------------------
- //
- // Copyright (c) 2002, Colin Granville
- //
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or
- // without modification, are permitted provided that the following
- // conditions are met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- //
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following
- // disclaimer in the documentation and/or other materials
- // provided with the distribution.
- //
- // * The name Colin Granville may not be used to endorse or promote
- // products derived from this software without specific prior
- // written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- // OF THE POSSIBILITY OF SUCH DAMAGE.
- //
- //--------------------------------------------------------------------------
-
- #include "Printer.h"
- #include "Document.h"
- #include "GuiTargets.h"
- #include "GuiWimpMessage.h"
- #include "GuiWindow.h"
- #include "GuiGadget.h"
- #include "GuiTask.h"
- #include "guilib:gfx.h"
- #include "guilib:ERROR.h"
- #include "DrawOutputDevice.h"
- #include "iostream.h"
- #include "GuiHourGlass.h"
- #include "UserEvents.h"
-
- class PrintJob
- {
- public:
- PrintJob(const char* filename,const char* title=0);
- ~PrintJob();
- void abort();
- operator void*() {return job?this:0;}
- int operator!() {return !job;}
-
- private:
- void close() {if (job) {_swix(OS_Find,_INR(0,1),0,job);job=0;}}
- int job;
- int oldJob;
- };
-
- //*************************************************************************
-
- PrintJob::PrintJob(const char* filename,const char* title)
- : job(0),
- oldJob(0)
- {
- if (_swix(OS_Find,_INR(0,1) | _OUT(0),0x8f,filename,&job) == 0 &&
- _swix(PDriver_SelectJob,_INR(0,1) | _OUT(0),job,title,&oldJob)==0) return;
-
- close();
- }
-
- //*************************************************************************
-
- PrintJob::~PrintJob()
- {
- if (!job) return;
- _swix(PDriver_EndJob,_IN(0),job);
- _swix(PDriver_SelectJob,_INR(0,1),oldJob,0);
- close();
- }
-
- //*************************************************************************
-
- void PrintJob::abort()
- {
- if (!job) return;
- _swix(PDriver_AbortJob,_IN(0),job);
- _swix(PDriver_SelectJob,_INR(0,1),oldJob,0);
- close();
- }
-
- //*************************************************************************
- //*************************************************************************
- //*************************************************************************
-
- class PrintArea
- {
- public:
- enum {FULL_PAGE,TOP_HALF,BOTTOM_HALF};
- PrintArea(Document& document,int page,int page_type,bool side2,const DocViewChoices&,bool isLandscape);
- _kernel_oserror* render(int id,GuiBBox& bounds);
-
- private:
- int id;
- DrawOutputDevice outDev;
- GuiTransform trfm;
- bool isBlank;
- };
-
-
- //*************************************************************************
-
- int nextId()
- {
- static int n=1;
- n^=1;
- return n;
- }
-
- PrintArea::PrintArea(Document& document,int page,int page_type, bool side2,
- const DocViewChoices& viewChoices,bool isLandscape)
- : id(nextId()),
- isBlank(page<=0)
- {
-
- if (page<0) return;
- int paper_width,paper_height;
- if (_swix(PDriver_PageSize,_OUTR(1,2),&paper_width,&paper_height)) return;
-
- if (page_type != FULL_PAGE) paper_height/=2;
- int y_offset=(page_type==TOP_HALF ? paper_height : 0);
-
- GuiBBox bounds;
- if (page > 0)
- {
- outDev.setMoreColours(gTrue);
- outDev.setNoImages(viewChoices.getNoImages());
- outDev.setNoText(viewChoices.getNoText());
- outDev.setNoImages(viewChoices.getNoDrawings());
- outDev.setNoText(viewChoices.getNoType3Fonts());
-
- int rotation=0;
- if (page_type != FULL_PAGE ||
- (isLandscape && page_type == FULL_PAGE) ) rotation=(side2 ? 90 : 270);
-
- document.getPage(page,&outDev,DrawOutputDevice::DPI,rotation);
-
- trfm.m0 = (1<<16);//1.08b9 (page_type == FULL_PAGE ? (1<<16) : 46341);// (1/root2)
- trfm.m1 = 0;
- trfm.m2 = 0; trfm.m3 = trfm.m0;
- trfm.m4 = 0; trfm.m5 = 0;
-
- outDev.getDrawFile().getBBox(bounds,&trfm);
- int wid=bounds.getWidth()*25/16; //convert to millipoints
- int ht =bounds.getHeight()*25/16;
-
- if (wid>paper_width || ht>paper_height)
- {
- double scale = (double)paper_width/(double)wid;
- double yscale= (double)paper_height/(double)ht;
- if (scale>yscale) scale=yscale;
-
- trfm.m0 = (int)((double)trfm.m0*scale);
- trfm.m3 = (int)((double)trfm.m3*scale);
-
- wid=(int)((double)wid*scale);
- ht=(int)((double)ht*scale);
- }
- trfm.m4=((paper_width-wid)/2)*16/25;
- trfm.m5=((paper_height-ht)/2+y_offset)*16/25;
- }
-
- bounds(0,y_offset/400,paper_width/400,(paper_height+y_offset)/400);
-
- int printer_trfm[4];
- printer_trfm[0]=(1<<16); printer_trfm[1]=0;
- printer_trfm[2]=0; printer_trfm[3]=printer_trfm[0];
-
- int origin[2];
- origin[0]=0;
- origin[1]=y_offset;
- _swix(PDriver_GiveRectangle,_INR(0,4),id,&bounds,printer_trfm,origin,0xFFFFFF00);
- }
-
- //*************************************************************************
-
- _kernel_oserror* PrintArea::render(int id_, GuiBBox& bounds)
- {
- if (id!=id_ || isBlank) return 0;
- return outDev.getDrawFile().render(&trfm,&bounds,0);
- }
-
- //*************************************************************************
- //*************************************************************************
- //*************************************************************************
-
- class PrinterProxy : public Node
- {
- public:
- virtual ~PrinterProxy();
- DECLARE_RTTI();
- };
-
-
- //*************************************************************************
- //*************************************************************************
- //*************************************************************************
-
- PrintData::PrintData()
- : document(0),
- copies(1),
- flags(0),
- from(1),
- to(1),
- start(0),
- end(0),
- sectionSize(0)
- {
- }
-
- //*************************************************************************
- //*************************************************************************
- //*************************************************************************
-
- class Printer
- {
- public:
- friend Printer& printer();
- bool print(const PrintData&);
- void release() {claimed=0;} //called by PrinterProxy when it is deleted
- private:
- Node* claimed;
- int myRef;
- GuiWindow mainWin;
- GuiActionButton continueButton;
- GuiActionButton cancelButton;
- GuiButton statusText;
- PrintData data;
-
-
- Printer();
- ~Printer();
-
- void finished();
- _kernel_oserror* printOneSide();
- _kernel_oserror* printSide(int page,int bottom_page,bool turn_clockwise);
- void startPrinting();
-
- GUI_DECLARE_EVENT_TARGETS(Printer);
-
- GuiToolboxTarget printSide2Target;
- Claim printSide2(GuiToolboxEvent&,const GuiIdBlock&);
-
- GuiWimpTarget protocolBounced;
- Claim noPrinter(GuiWimpPollBlock&, const GuiIdBlock&);
-
- GuiMessageTarget protocolA;
- Claim printFile(GuiWimpMessage&);
- Claim printTypeOdd(GuiWimpMessage&);
-
- GuiMessageTarget protocolB;
- Claim printError(GuiWimpMessage&);
- Claim dataSaveAck(GuiWimpMessage&);
-
- GuiNullTarget nullEvent;
- void startProtocol();
-
- };
-
- //*************************************************************************
-
- Printer::Printer()
- : claimed(0),
- mainWin("printStatus"),
- continueButton(mainWin,0),
- cancelButton(mainWin,2),
- statusText(mainWin,1),
- printSide2Target(&mainWin,User_PrintSide2,this,Printer::printSide2)
- {
- }
-
- //*************************************************************************
-
- Printer::~Printer() {}
-
- //*************************************************************************
-
- inline void set_short(char*& buf,int i)
- {
- *buf++=(i & 0xff);
- *buf++=((i>>8) & 0xff);
- }
-
- static void set_mouse_rectangle(const GuiBBox* box=0)
- {
- char buf[16];
- char*b=buf;
- *b++=1;
- set_short(b,(box ? box->xmin : 0));
- set_short(b,(box ? box->ymin : 0));
- set_short(b,(box ? box->xmax : gfx::screenwidth()-1));
- set_short(b,(box ? box->ymax : gfx::screenheight()-1));
- _swix(OS_Word,_INR(0,1),21,buf);
- }
-
- //*************************************************************************
-
- void Printer::finished()
- {
- protocolBounced.destroy();
- protocolA.destroy();
- protocolB.destroy();
- delete claimed;
- claimed=0;
- mainWin.hide();
- }
-
- //*************************************************************************
-
- bool Printer::print(const PrintData& d)
- {
- if (claimed) return 0;
- if (!d.document) return 0;
- data=d;
- claimed=data.document->addChild(new PrinterProxy); //keeps document open if no views
- if (!claimed) return 0;
-
- mainWin.showCentred();
- startPrinting();
- return 1;
- }
- //*************************************************************************
-
- void Printer::startPrinting()
- {
- statusText.setValue(guiTask().lookup("PRINT_ABORT:Press <Escape> to Abort"));
- cancelButton.fade(1);
- continueButton.fade(1);
- nullEvent(this,Printer::startProtocol);
- }
-
- //*************************************************************************
-
- void Printer::startProtocol()
- {
- nullEvent.destroy();
-
- protocolBounced(0,GuiWimp_EUserMessageAcknowledge,this,Printer::noPrinter);
- protocolA(GuiWimp_MPrintFile,this,Printer::printFile);
- protocolB(GuiWimp_MPrintError,this,Printer::printError);
-
- GuiWimpMessage mess;
- mess.hdr.size=44;
- myRef=mess.sendRecorded(GuiWimp_MPrintSave);
- }
-
- //*************************************************************************
-
- Claim Printer::noPrinter(GuiWimpPollBlock& wpb,const GuiIdBlock&)
- {
- GuiWimpMessage& mess= (GuiWimpMessage&) wpb;
- if (mess.hdr.myRef!=myRef) return DONT_CLAIM;
- finished();
- return CLAIM;
- }
-
- //*************************************************************************
-
- Claim Printer::printError(GuiWimpMessage& mess)
- {
- if (mess.hdr.yourRef!=myRef) return DONT_CLAIM;
- finished();
- if (mess.hdr.size==20)
- WARN("Printer Busy");
- else
- WARN((const _kernel_oserror*)&mess.data);
- return CLAIM;
- }
-
- //*************************************************************************
-
- Claim Printer::printFile(GuiWimpMessage& mess)
- {
- if (mess.hdr.yourRef!=myRef) return DONT_CLAIM;
-
- protocolBounced.destroy();
- protocolA(GuiWimp_MPrintTypeOdd,this,Printer::printTypeOdd);
- protocolB(GuiWimp_MDataSaveAck,this,Printer::dataSaveAck);
- return CLAIM;
- }
-
- //*************************************************************************
-
- Claim Printer::printTypeOdd(GuiWimpMessage& mess)
- {
- if (mess.hdr.yourRef!=myRef) return DONT_CLAIM;
- protocolA.destroy();
- protocolB.destroy();
- mess.reply(GuiWimp_MPrintTypeKnown);
-
- GuiHourglass hourglass;
- _kernel_oserror* err =printOneSide();
- if (err ||
- (data.flags & PrintData::IS_DOUBLE_SIDED)==0 ||
- data.flags & PrintData::IS_SIDE2)
- {
- finished();
- WARN(err);
- return CLAIM;
- }
-
- GuiGetWindowStateBlock state;
- mainWin.getState(state);
- set_mouse_rectangle(&state.visibleArea);
-
- statusText.setValue(guiTask().lookup("PRINT_SIDE2:Turn paper over"));
- cancelButton.fade(0);
- continueButton.fade(0);
- gfx::vdu(7);
- return CLAIM;
- }
-
- //*************************************************************************
-
- Claim Printer::printSide2(GuiToolboxEvent&,const GuiIdBlock& id_block)
- {
- set_mouse_rectangle();
- if (id_block.self.component!=continueButton.componentId())
- {
- finished();
- return CLAIM;
- }
- data.flags |= PrintData::IS_SIDE2;
- startPrinting();
- return CLAIM;
- }
- //*************************************************************************
-
- Claim Printer::dataSaveAck(GuiWimpMessage&)
- {
- finished();
- WARN("Printer Busy");
- return CLAIM;
- }
-
- //*************************************************************************
-
- _kernel_oserror* Printer::printOneSide()
- {
- PrintJob job("printer:","PDF");
- if (!job) return _kernel_last_oserror();
-
- if (_swix(PDriver_CheckFeatures,_INR(0,1),1<<29,1<<29)==0)
- {
- DrawOutputFontList::declareFonts();
- _swix(PDriver_DeclareFont,_INR(0,2),0,0,0);
- }
-
- int copies=data.copies;
- if (copies<1 || (data.flags & PrintData::IS_COLLATE)==0) copies=1;
- for (;copies;copies--)
- {
- int from = data.from;
- if (from==0) from=1;
-
- int to = data.to;
- if (to==0) to = data.document->getPageCount();
-
- if (data.flags & PrintData::IS_ALL)
- {
- from=1;
- to=data.document->getPageCount();
- }
- if (to<from) to=from;
-
- int number_of_sheets=to-from+1;
- int step=(data.flags & PrintData::IS_REVERSES_SHEETS?-1:1);
- int page=(data.flags & PrintData::IS_REVERSES_SHEETS?to:from);
- int fold_total=0;
- int turn_clockwise=0;
-
- if (data.flags & PrintData::IS_DOUBLE_SIDED)
- {
- int section_start=1;
- int section_end=data.document->getPageCount();
- if (data.flags & PrintData::IS_START_END)
- {
- if (data.start>section_start) section_start=data.start;
- if (data.end && data.end<section_end) section_end=data.end;
- }
- if (section_end<section_start) section_end=section_start;
- if (from<section_start) from=section_start;
- if (to>section_end) to=section_end;
- if (to<from) to=from;
-
- if (data.flags & PrintData::IS_PAMPHLET)
- {
- fold_total=((section_end-section_start)|3)+section_start*2;
- int first_page=(from-section_start)&~1;
- int last_page=(to-section_start)|1;
-
- int section_size =((section_end-section_start)|3);
-
- if (first_page>(section_size/2))
- {
- int n=section_size-first_page;
- first_page=section_size-last_page;
- last_page=n;
- }
- else if (last_page>(section_size/2))
- {
- last_page=section_size-last_page;
- if (last_page<first_page) first_page=last_page;
- last_page=section_size/2;
- }
-
- first_page&=~1;
- last_page&=~1;
- number_of_sheets=(last_page-first_page)/2 + 1;
-
- from=first_page+section_start;
- to=fold_total-from;
- if (to>section_end) to=section_end;
-
- page=last_page+section_start;
- step=-2;
- }
- else
- {
- from = ((from-section_start)&~1)+section_start;
- to = ((to-section_start)|1)+section_start;
- number_of_sheets = (to-from+1)/2;
- if (to>section_end) to=section_end;
-
- page=((to-section_start) &~1)+section_start;
- step=-2;
- }
-
- if (data.flags & PrintData::IS_SIDE2)
- {
- if ((data.flags & PrintData::IS_REVERSES_SHEETS)==0) {page+=1;turn_clockwise=1;}
- }
- else
- {
- if (data.flags & PrintData::IS_TURNS_PAPER_OVER) {page=from;step=2;}
- if (data.flags & PrintData::IS_REVERSES_SHEETS) {page+=1;turn_clockwise=1;}
- }
- }
-
- int i=0;
- _kernel_oserror* err=0;
- for (;i<number_of_sheets;i++)
- {
- int bottom_page=-1; //-1 no bottom_page, 0 blank bottom page;
- if (fold_total) bottom_page=fold_total-page;
- err=printSide((page>=from && page<=to ? page : 0),
- (bottom_page==-1 || (bottom_page>=from && bottom_page<=to) ? bottom_page : 0),
- turn_clockwise);
-
- if (err)
- {
- job.abort();
- return err;
- }
-
- GuiHourglass::percentage((i+1)*100/number_of_sheets);
- //cerr << (page>=from && page<=to ? page : 0) << ' '
- // << (bottom_page==-1 || (bottom_page>=from && bottom_page<=to) ? bottom_page : 0) << ' '
- // << turn_clockwise
- // << endl;
- page+=step;
- }
- }
- return 0;
- }
-
- //*************************************************************************
-
- _kernel_oserror* Printer::printSide(int top_page,int bottom_page,bool turn_clockwise)
- {
- PrintArea top(*data.document,top_page,
- (bottom_page<0 ? PrintArea::FULL_PAGE : PrintArea::TOP_HALF),
- turn_clockwise,data.viewChoices,data.flags & PrintData::IS_LANDSCAPE);
- PrintArea bottom(*data.document,bottom_page,PrintArea::BOTTOM_HALF,turn_clockwise,data.viewChoices,
- data.flags & PrintData::IS_LANDSCAPE);
- GuiBBox bounds;
- int more=0;
- int id;
- _kernel_oserror* err=0;
- int force_page=1;
- int copies=data.copies;
- if (copies <= 0 || data.flags & PrintData::IS_COLLATE) copies=1;
- for (err=_swix(PDriver_DrawPage,_INR(0,3)|_OUT(0)|_OUT(2),copies,&bounds,0,0,&more,&id);
- !err && more;
- err=_swix(PDriver_GetRectangle,_IN(1) |_OUT(0)|_OUT(2),&bounds,&more,&id))
- {
- if (force_page)
- {
- // force blank page by making sure something is printed on it
- // can't use 0xffffff00 as colour as it still thinks nothing is printed
- // so put the smallest of dots on the page
- static int path[]={2,0,0,8,0,1*256,0,0};
- static int trfm[]={(1<<16),0,0,(1<<16),0,0};
- gfx::gcol_bgr(0,0x0);
- trfm[4] = (bounds.xmin+8)*256-1;
- trfm[5] = (bounds.ymin+8)*256-1;
- err=_swix(Draw_Stroke,_INR(0,6),path,0,trfm,0,0,0,0);
- force_page=0;
- }
-
- err=top.render(id,bounds);
- if (!err) err=bottom.render(id,bounds);
- }
- return err;
- }
-
- //*************************************************************************
- //*************************************************************************
- //*************************************************************************
-
- PrinterProxy::~PrinterProxy()
- {
- printer().release();
- }
-
- DEFINE_RTTI_DERIVED(PrinterProxy,Node);
-
- //*************************************************************************
- //*************************************************************************
- //*************************************************************************
-
- Printer& printer()
- {
- static Printer p;
- return p;
- }
-
- //*************************************************************************
-
- bool Printer_print(const PrintData& data)
- {
- return printer().print(data);
- }
-
-